4. Visualização Geoespacial¶
A visualização de dados geoespaciais é uma ferramenta poderosa para comunicar padrões, tendências e insights espaciais. Com ela, cientistas de dados podem entender não apenas o "quê", mas o "onde".
Nesta seção, vamos explorar técnicas práticas para gerar mapas interativos com base em dados espaciais usando folium e geopandas.
4.1 Mapa de Pontos¶
Mapas de pontos são usados para mostrar onde eventos ou objetos estão localizados, como imóveis, sensores ou estabelecimentos comerciais.
import pandas as pd
import folium
# Carregar dados geocodificados de imóveis (já com latitude/longitude)
df = pd.read_csv("datasets/Singapore/geocodificados.csv")
df = df.dropna(subset=["latitude", "longitude"])
# Mapa básico centrado em Singapura
m = folium.Map(location=[1.3521, 103.8198], zoom_start=12, )
# Adicionar marcadores para cada imóvel
for _, row in df.iterrows():
folium.CircleMarker(
location=(row["latitude"], row["longitude"]),
radius=5,
color="blue",
fill=True,
fill_opacity=0.6,
popup=f"${row['resale_price']:.0f}"
).add_to(m)
m
4.2 Mapa Coropléticos
import geopandas as gpd
import folium
import pandas as pd
# Carregar dados dos imóveis
df = pd.read_csv("datasets/Singapore/geocodificados.csv")
df["preco_m2"] = df["resale_price"] / df["floor_area_sqm"]
# Padronizar nomes dos bairros
df["town_clean"] = df["town"].str.lower().str.strip()
# Calcular média de preço por região padronizada
media_por_town = df.groupby("town_clean")["preco_m2"].mean().reset_index()
# Carregar GeoJSON dos bairros
gdf_towns = gpd.read_file("datasets/Singapore/district_and_planning_area.geojson")
gdf_towns["planning_area_clean"] = gdf_towns["planning_area"].str.lower().str.strip()
# Merge com nomes padronizados
gdf_towns = gdf_towns.merge(media_por_town, left_on="planning_area_clean", right_on="town_clean")
# Criar mapa coroplético
m_choro = folium.Map(location=[1.3521, 103.8198], zoom_start=12)
folium.Choropleth(
geo_data="datasets/Singapore/district_and_planning_area.geojson",
data=gdf_towns,
columns=["planning_area", "preco_m2"],
key_on="feature.properties.planning_area",
fill_color="YlGnBu",
fill_opacity=0.7,
line_opacity=0.2,
legend_name="Preço médio por m² (SGD)"
).add_to(m_choro)
m_choro
4.2 Mapa com Classificação por Preço/m²¶
Vamos classificar os imóveis como "Barato", "Médio" ou "Caro" com base nos quartis do preço por metro quadrado (preço/m²), e usar cores diferentes para cada categoria.
# Calcular preço por metro quadrado
df["preco_m2"] = df["resale_price"] / df["floor_area_sqm"]
# Definir os quartis
q1 = df["preco_m2"].quantile(0.25)
q3 = df["preco_m2"].quantile(0.75)
# Função para classificar
def classificar_preco(valor):
if valor < q1:
return "Barato"
elif valor < q3:
return "Médio"
else:
return "Caro"
# Aplicar classificação e definir cores
df["categoria"] = df["preco_m2"].apply(classificar_preco)
cores = {"Barato": "green", "Médio": "orange", "Caro": "red"}
# Mapa com cores por categoria
m2 = folium.Map(location=[1.3521, 103.8198], zoom_start=12)
df = df.dropna()
for _, row in df.iterrows():
folium.CircleMarker(
location=(row["latitude"], row["longitude"]),
radius=5,
color=cores[row["categoria"]],
fill=True,
fill_opacity=0.75,
popup=f"{row['categoria']} - ${row['preco_m2']:.0f}/m²"
).add_to(m2)
m2
4.3 Heatmap¶
Mapas de calor são úteis para visualizar a concentração de eventos ou objetos em uma área. Neste exemplo, vamos criar um heatmap para mostrar a densidade de imóveis.
from folium.plugins import HeatMap
# Mapa de calor da densidade de imóveis
m3 = folium.Map(location=[1.3521, 103.8198], zoom_start=12)
HeatMap(data=df[["latitude", "longitude"]]).add_to(m3)
m3
import pandas as pd
import folium
from folium.plugins import MarkerCluster
# Carregar os dados
df = pd.read_csv("datasets/Singapore/geocodificados.csv")
# Remover registros com coordenadas ausentes
df = df.dropna(subset=["latitude", "longitude"])
# Criar mapa base
m = folium.Map(location=[1.3521, 103.8198], zoom_start=12)
# Criar o cluster de marcadores
marker_cluster = MarkerCluster().add_to(m)
# Adicionar os pontos ao cluster
for _, row in df.iterrows():
popup_text = f"""
<b>Preço:</b> ${row['resale_price']:,.0f}<br>
<b>Área:</b> {row['floor_area_sqm']} m²<br>
<b>Tipo:</b> {row['flat_type']}<br>
<b>Bairro:</b> {row['town']}
"""
folium.Marker(
location=(row["latitude"], row["longitude"]),
popup=folium.Popup(popup_text, max_width=250)
).add_to(marker_cluster)
# Exibir o mapa
m
visualizacao temporal com mapa
from folium.plugins import TimestampedGeoJson
import folium
import pandas as pd
# Carregar os dados
df = pd.read_csv("datasets/Singapore/geocodificados.csv")
# Corrigir o tipo de dado e criar timestamp por lease
df["lease_date"] = pd.to_datetime(df["lease_commence_date"].astype(int).astype(str) + "-01-01")
df["timestamp"] = df["lease_date"].dt.strftime("%Y-%m-%d")
# Construir GeoJSON
features = []
for _, row in df.dropna(subset=["latitude", "longitude"]).iterrows():
feature = {
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [row["longitude"], row["latitude"]],
},
"properties": {
"time": row["timestamp"],
"popup": f"{row['town']}<br>Lease: {row['lease_commence_date']}<br>Preço: ${row['resale_price']:,.0f}",
"icon": "circle",
"iconstyle": {
"fillColor": "blue",
"fillOpacity": 0.6,
"stroke": "true",
"radius": 5
},
},
}
features.append(feature)
geojson = {
"type": "FeatureCollection",
"features": features
}
# Criar mapa
m_time = folium.Map(location=[1.3521, 103.8198], zoom_start=12)
TimestampedGeoJson(geojson, period="P1Y", add_last_point=True).add_to(m_time)
m_time
from folium.plugins import HeatMapWithTime
import pandas as pd
import folium
# Carregar e preparar os dados
df = pd.read_csv("datasets/Singapore/geocodificados.csv")
df = df.dropna(subset=["latitude", "longitude", "lease_commence_date"])
df["lease_commence_date"] = df["lease_commence_date"].astype(int)
# Agrupar os imóveis por ano (ex: de 1980 a 2020)
anos = sorted(df["lease_commence_date"].unique())
heat_data = []
for ano in anos:
subset = df[df["lease_commence_date"] == ano]
pontos = subset[["latitude", "longitude"]].values.tolist()
heat_data.append(pontos)
# Criar o mapa
m_heat = folium.Map(location=[1.3521, 103.8198], zoom_start=12)
# Adicionar heatmap com animação temporal
HeatMapWithTime(
heat_data,
index=anos,
auto_play=True,
radius=10,
max_opacity=0.8
).add_to(m_heat)
# Garantir que o campo esteja como inteiro
df["lease_commence_date"] = df["lease_commence_date"].astype(int)
# Contar lançamentos por ano
contagem = df["lease_commence_date"].value_counts().sort_index()
# Mostrar o ano com mais lançamentos
ano_top = contagem.idxmax()
qtd_top = contagem.max()
print(f"O ano com mais lançamentos foi {ano_top}, com {qtd_top} imóveis.")
m_heat
O ano com mais lançamentos foi 1985, com 92 imóveis.